package com.ccp.dev.system.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.basic.web.query.QueryFilter;
import com.ccp.dev.core.util.*;
import com.ccp.dev.system.consts.FileManagementContants;
import com.ccp.dev.system.dao.DictionaryDao;
import com.ccp.dev.system.dao.FileManagementDao;
import com.ccp.dev.system.dao.SysUserDao;
import com.ccp.dev.system.model.Dictionary;
import com.ccp.dev.system.model.FileManagement;
import com.ccp.dev.system.model.SysFile;
import com.ccp.dev.system.model.SysUser;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipInputStream;

/**
 * file_management 信息操作服务类
 *
 * @author zhaowj
 * @date 2020-03-22 14:11:51
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class FileManagementService extends BaseService<FileManagement> {

    @Resource
    private FileManagementDao fileManagementDao;

    @Resource
    private RightManageService rightManageService;

    @Resource
    private FileManagementLogService fileManagementLogService;

    @Resource
    private DictionaryDao dictionaryDao;

    @Resource
    private SysUserDao sysUserDao;



    /**
     * 获取目录结构树
     *
     * @param treeType 父节点类型 1物理树目录节点 2逻辑归类树目录节点
     * @return 所有的树
     */
    public List<Map<String, Object>> getFolderTree(int treeType, String basePath) {
        //查询所有目录节点信息
        List<FileManagement> list = fileManagementDao.getManageByCondition(FileManagementContants.FILE_TYPE_FOLDER, treeType);
        List<Map<String, Object>> nodeList = new ArrayList<>();
        for (FileManagement item : list) {
            Map<String, Object> treeMap = new HashMap<>();
            //如果目录的创建人是当前用户，则需要显示此目录节点
            if (ContextUtil.getCurrentUserId().equals(item.getUploadPersonId())) {
                addToNodeList(basePath, nodeList, item, treeMap);
            } else {
                String permissionJson = item.getManageField();
                //如果当前节点有设置权限，则进行权限过滤
                if (StringUtils.isNotEmpty(permissionJson)) {
                    if (checkNodeRight(item.getId(), permissionJson)) {
                        addToNodeList(basePath, nodeList, item, treeMap);
                    }
                } else {
                    //如果当前节点未设置权限，则遍历有设置权限的父节点
                    FileManagement parentNode = getParentNodeWithPermission(item.getParentId(), list);
                    if (parentNode != null) {
                        String parentPermissionJson = parentNode.getManageField();
                        //如果父节点可以显示到列表中，则此子节点默认继承父节点的权限，也可以进行显示
                        if (checkNodeRight(parentNode.getId(), parentPermissionJson)) {
                            addToNodeList(basePath, nodeList, item, treeMap);
                        }
                    }
                }
            }
        }
        return nodeList;
    }

    /**
     * 将可显示的节点添加到List中
     *
     * @param basePath 图标路径
     * @param retList  待显示node节点list
     * @param item     当前节点
     * @param treeMap  map数据容器
     */
    private void addToNodeList(String basePath, List<Map<String, Object>> retList, FileManagement item, Map<String, Object> treeMap) {
        int parentType = item.getParentType();
        treeMap.put("id", item.getId());
        treeMap.put("pId", item.getParentId());
        treeMap.put("name", item.getFileName());
        treeMap.put("parentType", item.getParentType());
        if (!"".equals(basePath) && parentType == FileManagementContants.PARENT_TYPE_LOGICTREE) {
            //设置归类逻辑树图标
            treeMap.put("icon", basePath + "systemStatic/images/tree_folder.gif");
        }
        retList.add(treeMap);
    }

    /**
     * 判断是否有显示权限
     *
     * @param nodeID         当前节点id
     * @param permissionJson 权限JSON串
     * @return
     */
    private Boolean checkNodeRight(String nodeID, String permissionJson) {
        if (StringUtils.isEmpty(permissionJson)) {
            return false;
        }
        Map<String, Object> rightMap = rightManageService.getRightMap(ContextUtil.getCurrentUser().getUserId(), ContextUtil.getCurrentOrgId());
        Map<String, Boolean> managePermission = rightManageService.getManagePermission(RightManageService.RIGHT_TYPE_MANAGE, permissionJson, rightMap);
        if (managePermission.get(String.valueOf(nodeID)) == null || managePermission.get(String.valueOf(nodeID))) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取树的节点和权限
     *
     * @param fileType 文件类型：1文件夹  2文件
     * @param treeType 父节点类型 1物理树目录节点 2逻辑归类树目录节点
     * @return 包含权限的文件对象list
     */
    public List<FileManagement> queryManageByFileTypeAndTreeType(int fileType, int treeType) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("fileType", fileType);
        params.put("parentType", treeType);
        return fileManagementDao.queryManageByCondition(params);
    }

    /**
     * 获取树的节点和权限
     *
     * @param fileType 文件类型：1文件夹  2文件
     * @param parentId 父节点id
     * @return 包含权限的文件对象list
     */
    public List<FileManagement> queryManageByFileTypeAndParentId(int fileType, String parentId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("fileType", fileType);
        params.put("parentId", parentId);
        return fileManagementDao.queryManageByCondition(params);
    }

    /**
     * 循环到存在权限设置的父节点
     *
     * @param parentNodeID 当前节点的父节点ID
     * @param fileList     查询到的所有树节点数据
     * @return 父节点数据
     */
    public FileManagement getParentNodeWithPermission(String parentNodeID, List<FileManagement> fileList) {
        for (FileManagement fileManagement : fileList) {
            //如果可以获取到父节点，且父节点的权限设置不为空，则返回当前父节点
            if (parentNodeID.equals(fileManagement.getId())) {
                if (StringUtil.isNotEmpty(fileManagement.getManageField())) {
                    return fileManagement;
                } else {
                    return getParentNodeWithPermission(fileManagement.getParentId(), fileList);
                }
            }
        }
        return null;
    }

    /**
     * 通过父节点查询下一级所有文件
     *
     * @param parentType  树类型
     * @param basePath
     * @param queryFilter 查询条件
     * @return 分页数据
     */
    public List<FileManagement> getFilesPageByParentId(String basePath, int parentType, QueryFilter queryFilter) {
        // 获取当前用户
        SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
        int[] fileSecretLevels = FileManagementContants.getFileSecretByUserSecret(sysUser.getPrivacyLevel());
        queryFilter.addFilter("fileSecretLevels", fileSecretLevels);
        List<FileManagement> fileList = fileManagementDao.getFilesByFilterCondition(queryFilter);
        List<FileManagement> retList = new ArrayList<>();
        List<Map<String, Object>> viewList = getFolderTree(parentType, basePath);
        for (FileManagement item : fileList) {
            Dictionary dic = dictionaryDao.getDicItem(FileManagementContants.FILE_SECRET_TYPE, String.valueOf(item.getFileSecretLevel()));
            if (BeanUtils.isNotEmpty(dic)) {
                item.setFileSecretStr(dic.getItemName());
            }
            if (item.getFileType() == FileManagementContants.FILE_TYPE_FILE) {
                retList.add(item);
            } else {
                for (Map<String, Object> map : viewList) {
                    //过滤到没有权限的目录节点
                    if (item.getId().equals(String.valueOf(map.get("id")))) {
                        retList.add(item);
                    }
                }
            }
        }
        return retList;
    }

    /**
     * 默认查询物理树中最早建的根节点的
     *
     * @param parentId 父节点id
     * @return 分页数据
     */

    public String initPageList(String parentId) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", parentId);
        //父节点类型 1物理树目录节点 2逻辑归类树目录节点
        params.put("parentType", FileManagementContants.PARENT_TYPE_TREE);
        List<FileManagement> fileList = fileManagementDao.getFilesByCondition(params);
        String queryId = FileManagementContants.JSP_PARENT_ID;
        if (fileList.size() > 0) {
            queryId = fileList.get(0).getId();
        }
        return queryId;
    }

    /**
     * 添加文件映射
     *
     * @param fileIds  要指定的文件id
     * @param parentId 要映射到的目录节点id
     * @throws Exception
     */
    public String addFileMapping(String[] fileIds, String parentId,String alias ) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params.put("fileIds", fileIds);
        List<FileManagement> fileList = fileManagementDao.getFilesByCondition(params);
        String msg = "";
        for (FileManagement item : fileList) {
            if (isExistMapping(item.getFileStorge() , item.getFileName() , item.getFileFormat() , parentId)) {
                msg += item.getFileName() + ": 已经映射过当前文件夹;";
                continue;
            }
            //保存原文件的fileId，为了解密用
            item.setRemark(String.valueOf(item.getId()));
            String fileId = UUIDUtils.getUUIDFor32();
            item.setId(fileId);
            //给每个对象重新设置父节点的值
            item.setParentId(parentId);
            item.setParentType(FileManagementContants.PARENT_TYPE_LOGICTREE);
            item.setUploadDate(new Date());
            item.setAlias(alias);
            fileManagementDao.add(item);
        }
        return msg;
    }

    /**
     * 查看此文件是否已经映射过此文件夹
     * @param fileName  文件名
     * @param fileFormat  文件后缀
     * @param fileStorge  文件储存路径
     * @param parentId  父id
     * @return 0不存在映射 1存在映射
     */
    public boolean isExistMapping(String fileStorge , String fileName , String fileFormat, String parentId) {
        Map<String, Object> params = new HashMap<>();
        params.put("fileStorge", fileStorge);
        params.put("parentId", parentId);
        params.put("fileName", fileName);
        params.put("fileFormat", fileFormat);
        List<FileManagement> fileList = fileManagementDao.queryExistMapping(params);
        if (fileList.size() > 0) {
            return FileManagementContants.FILE_MAPPING_TRUE;
        }
        return FileManagementContants.FILE_MAPPING_FALSE;
    }

    /**
     * 获取文件密级属性值
     *
     * @param fileSecretLevels
     * @return
     */
    public List<Map<String, Object>> getFileSecretDic(int[] fileSecretLevels) {
        List<Map<String, Object>> fileSecretList = new ArrayList<>();
        for (int i = 0; i < fileSecretLevels.length; i++) {
            Map<String, Object> map = new HashMap();
            Dictionary dic = dictionaryDao.getDicItem(FileManagementContants.FILE_SECRET_TYPE, String.valueOf(fileSecretLevels[i]));
            map.put("key", dic.getItemValue());
            map.put("fileSecret", dic.getItemName());
            fileSecretList.add(map);
        }
        return fileSecretList;
    }

    /**
     * 判断文件名称是否重复
     *
     * @param fileName   新文件名
     * @param parentId   父节点ID
     * @param fileFormat 文件扩展名
     * @param fileType   文件类型
     * @param fileId     文件ID
     * @param alias      映射文件别名
     * @return 文件名称重复结果
     */
    public String fileNameExist(String fileName, String parentId, String fileFormat, int fileType, String fileId, String alias) {
        if (!fileId.isEmpty()) {
            //先判断文件是否存在
            FileManagement file = fileManagementDao.getById(fileId);
            if (file == null) {
                return FileManagementContants.FILE_REMANE_NO_FILE;
            }
            //判断名称是否重复
            //获取当前文件父节点
            parentId = String.valueOf(file.getParentId());
            //获取当前文件类型
            fileType = file.getFileType();
            //获取当前文件扩展名
            fileFormat = "null".equals(String.valueOf(file.getFileFormat())) ? "" : String.valueOf(file.getFileFormat());
        }
        if (StringUtil.isNotEmpty(fileName) || StringUtil.isNotEmpty(alias)) {
            Map<String, Object> params = new HashMap<>();
            params.put("fileName", fileName);
            params.put("id", fileId);
            params.put("parentId", parentId);
            params.put("fileFormat", fileFormat);
            params.put("fileType", fileType);
            params.put("alias", alias);
            List<FileManagement> otherFile = fileManagementDao.getFileByFileName(params);
            if (otherFile.size() > 0) {
                return FileManagementContants.FILE_REMANE_NAMEREPEAT;
            }
        }
        return FileManagementContants.FILE_REMANE_NOREPEAT;
    }

    /**
     * 添加目录和文件中公共赋值部分
     *
     * @param fileManagement 文件对象
     * @throws Exception
     */
    public void addFileManagement(FileManagement fileManagement) throws Exception {
        // 获取当前用户
        SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
        fileManagement.setUploadDate(new Date());
        fileManagement.setUploadPersonId(sysUser.getUserId());
        fileManagement.setUploadPersonName(sysUser.getFullName());
        fileManagementDao.add(fileManagement);
        fileManagementLogService.addLog(fileManagement.getId(), fileManagement.getFileName(), fileManagement.getFileStorge(), FileManagementContants.FILE_OPERATOR_UPLOAD);
    }

    /**
     * 修改文件夹名称
     *
     * @param fileManagement  文件对象
     * @return 修改结果
     */
    public String editFolder(FileManagement fileManagement) throws Exception {
        //返回修改结果
        String result = FileManagementContants.FILE_REMANE_ERROR;
        if(StringUtil.isEmpty(fileManagement.getId())|| StringUtil.isEmpty(fileManagement.getFileName())){
            return result;
        }
        String fileId = fileManagement.getId();
        String fileName = fileManagement.getFileName();
        //先判断文件是否存在
        FileManagement file = fileManagementDao.getById(fileId);
        if (file == null) {
            return FileManagementContants.FILE_REMANE_NO_FILE;
        }
        //判断名称是否重复
        //获取当前文件父节点
        String parentId = String.valueOf(file.getParentId());
        //获取当前文件扩展名
        String fileFormat = "null".equals(String.valueOf(file.getFileFormat())) ? "" : String.valueOf(file.getFileFormat());
        //获取当前文件类型
        if (StringUtil.isNotEmpty(fileName)) {
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("fileName", fileName);
            paramsMap.put("id", fileId);
            paramsMap.put("parentId", parentId);
            List<FileManagement> otherFile = fileManagementDao.getFileByFileName(paramsMap);
            if (otherFile.size() > 0) {
                return FileManagementContants.FILE_REMANE_NAMEREPEAT;
            }
        }
        //修改文件名称
        if (null != fileName) {
            file.setFileName(fileName);
        }
        //找到对应的映射文件 原文件名称和摘要修改了,对应的映射文件也要修改
        int sqlResult = fileManagementDao.update(file);
        if (sqlResult > 0) {
            if (StringUtil.isEmpty(fileName)) {
                fileName = file.getFileName();
            }
            //增加日志
            fileManagementLogService.addLog(fileId, fileName, file.getFileStorge(), FileManagementContants.FILE_OPERATOR_RENAME);
            result = FileManagementContants.FILE_REMANE_SUCCESS;
        }
        return result;
    }

    /**
     * 修改文件/文件夹名称 摘要
     *
     * @param fileManagement 文件对象
     * @return 修改结果
     */
    public String editFile(FileManagement fileManagement) throws Exception {
        String fileId = fileManagement.getId();
        String fileName = fileManagement.getFileName();
        String alias = fileManagement.getAlias();
        String fileKeywords = fileManagement.getFileKeywords();
        int fileSecretLevel = fileManagement.getFileSecretLevel();
        //先判断文件是否存在
        FileManagement file = fileManagementDao.getById(fileId);
        if (file == null) {
            return FileManagementContants.FILE_REMANE_NO_FILE;
        }
        //判断名称是否重复
        //获取当前文件父节点
        String parentId = String.valueOf(file.getParentId());
        //获取当前文件扩展名
        String fileFormat = "null".equals(String.valueOf(file.getFileFormat())) ? "" : String.valueOf(file.getFileFormat());
        //获取当前文件类型
        int fileType = file.getFileType();
        if (StringUtil.isNotEmpty(fileName)) {
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("fileName", fileName);
            paramsMap.put("id", fileId);
            paramsMap.put("parentId", parentId);
            paramsMap.put("fileFormat", fileFormat);
            paramsMap.put("fileType", fileType);
            paramsMap.put("alias", alias);
            List<FileManagement> otherFile = fileManagementDao.getFileByFileName(paramsMap);
            if (otherFile.size() > 0) {
                return FileManagementContants.FILE_REMANE_NAMEREPEAT;
            }
        }
        if (null != fileKeywords) {
            file.setFileKeywords(fileKeywords);
        }
        if (null != fileManagement.getOrderNumber()) {
            String orderNumber = fileManagement.getOrderNumber();
            file.setOrderNumber(fileManagement.getOrderNumber());
            if (StringUtil.isNotEmpty(orderNumber)) {
                Map<String, Object> orderNumMap = new HashMap<>();
                orderNumMap.put("orderNumber", Integer.parseInt(orderNumber));
                //查询orderNumber是否已经存在
                List<FileManagement> list = fileManagementDao.getFilesByCondition(orderNumMap);
                if (list.size() > 0) {
                    //如果存在此orderNumber 则把大于等于orderNumber的记录都加1
                    Map<String, Object> updateParams = new HashMap<>();
                    updateParams.put("orderNumber", Integer.parseInt(orderNumber));
                    updateParams.put("parentId", file.getParentId());
                    fileManagementDao.updateOrderNumbers(updateParams);
                }
            }
        }
        //修改文件名称
        if (null != fileName) {
            file.setFileName(fileName);
            //修改密级
            file.setFileSecretLevel(fileSecretLevel);
        }
        //找到对应的映射文件 原文件名称和摘要修改了,对应的映射文件也要修改
        if (StringUtil.isEmpty(alias)) {
            Map<String, Object> updateMappingParams = new HashMap<>();
            updateMappingParams.put("fileId", fileId);
            updateMappingParams.put("fileName", fileName);
            updateMappingParams.put("fileKeywords", fileKeywords);
            updateMappingParams.put("fileSecretLevel",fileSecretLevel);
            fileManagementDao.updateMappings(updateMappingParams);
        }else {
            file.setAlias(alias);
        }
        int sqlResult = fileManagementDao.update(file);
        //返回修改结果
        String result = FileManagementContants.FILE_REMANE_ERROR;
        if (sqlResult > 0) {
            if (StringUtil.isEmpty(fileName)) {
                fileName = file.getFileName();
            }
            //增加日志
            fileManagementLogService.addLog(fileId, fileName, file.getFileStorge(), FileManagementContants.FILE_OPERATOR_RENAME);
            result = FileManagementContants.FILE_REMANE_SUCCESS;
        }
        return result;
    }

    /**
     * 删除文件/文件夹
     *
     * @param fileIds 文件/文件夹ID 多个时用","隔开
     * @return
     */
    public String deleteFile(String fileIds) throws Exception {
        //获取所有待删除数据ID和文件路径
        String userId = ContextUtil.getCurrentUserId();
        String[] deleteFiles = fileIds.split(",");
        List deleteAllFileId = new ArrayList();
        List deleteAllFilePaths = new ArrayList();
        int treeType = FileManagementContants.PARENT_TYPE_TREE;
        if (deleteFiles.length == 1) {
            //先判断文件是否存在
            FileManagement file = fileManagementDao.getById(fileIds);
            if (file == null) {
                return FileManagementContants.DELETE_FILE_NO_FILE;
            }
            treeType = file.getParentType();
            //若删除对象为文件 则直接删除
            if (file.getFileType() == FileManagementContants.FILE_TYPE_FILE && userId.equals(file.getUploadPersonId())) {
                deleteAllFileId.add(file.getId());
                deleteAllFilePaths.add(file.getFileStorge());
            }
            //若删除对象为文件夹 则递归遍历 并删除
            else if (file.getFileType() == FileManagementContants.FILE_TYPE_FOLDER && userId.equals(file.getUploadPersonId())) {
                List deleteIds = new ArrayList();
                deleteIds.add(fileIds);
                List deletePaths = new ArrayList();
                Map<String, Object> deleteMap = new HashMap<>();
                deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, deleteIds);
                deleteMap.put(FileManagementContants.DELETE_FILE_DELETEPATHS, deletePaths);
                Map<String, Object> params = new HashMap<>();
                params.put("parentId", file.getId());
                List<FileManagement> childFileList = fileManagementDao.getFileByFileName(params);
                if (childFileList.size() > 0) {
                    this.getDeleteFileIds(childFileList, deleteMap, userId);
                }
                if (FileManagementContants.DELETE_FILE_CANTDELETE.equals(deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS))) {
                    return FileManagementContants.DELETE_FILE_OTHER_USER_FILE;
                }
                deleteAllFileId = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS);
                deleteAllFilePaths = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEPATHS);
            } else {
                return FileManagementContants.DELETE_FILE_OTHER_USER_FILE;
            }
        } else if (deleteFiles.length > 1) {
            //若同时删除多个文件/文件夹
            List deleteIds = new ArrayList();
            List deletePaths = new ArrayList();
            Map<String, Object> deleteMap = new HashMap<String, Object>();
            deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, deleteIds);
            deleteMap.put(FileManagementContants.DELETE_FILE_DELETEPATHS, deletePaths);
            for (int i = 0; i < deleteFiles.length; i++) {
                //先判断文件是否存在
                FileManagement file = fileManagementDao.getById(deleteFiles[i]);
                if (file == null) {
                    return FileManagementContants.DELETE_FILE_NO_FILE;
                }
                //若删除对象为文件 则记录id和路径
                if (file.getFileType() == FileManagementContants.FILE_TYPE_FILE && userId.equals(file.getUploadPersonId())) {
                    List currentId = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS);
                    List currentPath = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEPATHS);
                    currentId.add(file.getId());
                    currentPath.add(file.getFileStorge());
                    deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, currentId);
                    deleteMap.put(FileManagementContants.DELETE_FILE_DELETEPATHS, currentPath);
                }
                //若删除对象为文件夹 则递归遍历 并删除
                else if (file.getFileType() == FileManagementContants.FILE_TYPE_FOLDER && userId.equals(file.getUploadPersonId())) {
                    List currentId = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS);
                    currentId.add(file.getId());
                    deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, currentId);
                    Map<String, Object> paramsMap = new HashMap<>();
                    paramsMap.put("parentId", file.getId());
                    List<FileManagement> childFileList = fileManagementDao.getFileByFileName(paramsMap);
                    if (childFileList.size() > 0) {
                        this.getDeleteFileIds(childFileList, deleteMap, userId);
                    }
                    if (FileManagementContants.DELETE_FILE_CANTDELETE.equals(deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS))) {
                        return FileManagementContants.DELETE_FILE_OTHER_USER_FILE;
                    }
                } else {
                    return FileManagementContants.DELETE_FILE_OTHER_USER_FILE;
                }
            }
            deleteAllFileId = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS);
            deleteAllFilePaths = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEPATHS);
        }
        //增加删除日志
        if (deleteAllFileId.size() > 0) {
            for (int i = 0; i < deleteAllFileId.size(); i++) {
                String fileId = String.valueOf(deleteAllFileId.get(i));
                FileManagement fileLog = fileManagementDao.getById(fileId);
                fileManagementLogService.addLog(fileLog.getId(), fileLog.getFileName(), fileLog.getFileStorge(), FileManagementContants.FILE_OPERATOR_DELETE);
            }
        }
        //删除数据库记录

        int sqlResult = fileManagementDao.deleteByIds(deleteAllFileId);
        //删除映射关系数据 删除逻辑树某个节点的时候 不能删除物理树上的文件记录
        if (deleteAllFilePaths.size() > 0 && treeType == FileManagementContants.PARENT_TYPE_TREE)  {
            fileManagementDao.deleteByPaths(deleteAllFilePaths);
        }
        //删除本地文件 除逻辑树某个节点的时候 不能删除物理树上的本地文件
        if (deleteAllFilePaths.size() > 0 && treeType == FileManagementContants.PARENT_TYPE_TREE) {
            final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1,
                    new BasicThreadFactory.Builder().namingPattern("deleteFile-schedule-pool-%d").daemon(true).build());
            final List finalDeleteAllFilePaths = deleteAllFilePaths;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    int fileSize = finalDeleteAllFilePaths.size();
                    String attachPath = SysFileService.getBasePath();
                    for (int i = 0; i < fileSize; i++) {
                        File deleteFile = new File(attachPath +"\\" + (String) finalDeleteAllFilePaths.get(i));
                        if (deleteFile.exists() && deleteFile.canWrite()) {
                            deleteFile.delete();
                            finalDeleteAllFilePaths.remove(i);
                            i--;
                        }
                    }
                    if (finalDeleteAllFilePaths.size() < 1) {
                        service.shutdown();
                    }
                }
            };
            // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间 默认设置第一次删除时间为1分钟 若文件仍被使用 则每30分钟检测一次
            service.scheduleAtFixedRate(runnable, 1, 30, TimeUnit.MINUTES);
        }
        //返回删除结果
        String result = FileManagementContants.DELETE_FILE_ERROR;
        if (sqlResult > 0) {
            return FileManagementContants.DELETE_FILE_SUCCESS;
        }
        return result;
    }

    /**
     * 递归判断需要删的文件是否为该用户所有 且返回所有需要删除的数据ID
     *
     * @param fileList  需要递归的文件夹/文件列表
     * @param deleteMap 所有需要删除的数据和文件路径
     * @param userId    执行删除的人员
     * @return MAP 所有需要删除的数据ID和文件路径
     */
    private Map getDeleteFileIds(List<FileManagement> fileList, Map<String, Object> deleteMap, String userId) {
        List deleteIds = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS);
        List deletePath = (List) deleteMap.get(FileManagementContants.DELETE_FILE_DELETEPATHS);
        for (int i = 0; i < fileList.size(); i++) {
            FileManagement currentFile = fileList.get(i);
            //若文件上传人不是本人 则返回删除失败
            if (!userId.equals(currentFile.getUploadPersonId())) {
                deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, FileManagementContants.DELETE_FILE_CANTDELETE);
                return deleteMap;
            }
            //若为文件类型 则拼接文件ID
            if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FILE) {
                deleteIds.add(currentFile.getId());
                deletePath.add(currentFile.getFileStorge());
            }
            //若为文件夹 则继续递归
            if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FOLDER) {
                deleteIds.add(currentFile.getId());
                Map<String, Object> params = new HashMap<>();
                params.put("parentId", currentFile.getId());
                List<FileManagement> currentList = fileManagementDao.getFileByFileName(params);
                this.getDeleteFileIds(currentList, deleteMap, userId);
                if (FileManagementContants.DELETE_FILE_CANTDELETE.equals(deleteMap.get(FileManagementContants.DELETE_FILE_DELETEIDS))) {
                    return deleteMap;
                }
            }
        }
        deleteMap.put(FileManagementContants.DELETE_FILE_DELETEIDS, deleteIds);
        deleteMap.put(FileManagementContants.DELETE_FILE_DELETEPATHS, deletePath);
        return deleteMap;
    }

    /**
     * 下载文件
     *
     * @param fileIds 需要下载的文件/文件夹ID 多个ID使用逗号隔开
     * @return 文件下载路径
     */
    public String downloadFile(String fileIds) throws Exception {
        //获取用户密级
        SysUser currentUser = (SysUser) ContextUtil.getCurrentUser();
        int[] fileSecreatLevel = FileManagementContants.getFileSecretByUserSecret(currentUser.getPrivacyLevel());
        String downloadPath = "";
        String[] downloadFiles = fileIds.split(",");
        if (downloadFiles.length == 1) {
            //先判断文件是否存在
            FileManagement file = fileManagementDao.getById(fileIds);
            if (file == null) {
                return FileManagementContants.DELETE_FILE_NO_FILE;
            }
            String fileId = file.getId();
            //若下载对象为文件 则直接解压后下载
            if (file.getFileType() == FileManagementContants.FILE_TYPE_FILE) {
                //获取文件路径
                String attachPath = SysFileService.getBasePath();
                String sourcePath = attachPath + File.separator + file.getFileStorge();
                //临时解压路径
                String pathToUnZip = StringUtil.trimSufffix(attachPath, File.separator) + File.separator + fileId;
                //获取文件真实ID 若为逻辑树文件 则获取remark值
                String fileRealId = String.valueOf(fileId);
                if (file.getParentType() == FileManagementContants.PARENT_TYPE_LOGICTREE) {
                    fileRealId = file.getRemark();
                }
                SysUser sysUser = sysUserDao.getById(file.getUploadPersonId());
                String filePassword = SysFile.PASSWORD_PROJECT_NAME + "_" + sysUser.getAccount() + "_" + fileRealId;
                ZipUtil.unZip(sourcePath, pathToUnZip, filePassword);
                //下载文件
                downloadPath = pathToUnZip + File.separator + fileRealId + "." + file.getFileFormat();
            } else if (file.getFileType() == FileManagementContants.FILE_TYPE_FOLDER) {
                String attachPath = SysFileService.getBasePath();
                //新建下载目录
                //为保证目录不重复 生成时间戳
                long time = System.currentTimeMillis();
                downloadPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator + time + File.separator + file.getFileName() + ".zip";
                String folderPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator + time + File.separator + file.getFileName();
                File dir = new File(folderPath);
                dir.mkdirs();
                //获取目录下所有文件
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("parentId", fileId);
                List<FileManagement> childFileList = fileManagementDao.getFileByFileName(params);
                int childSize = childFileList.size();
                for (int i = 0; i < childSize; i++) {
                    FileManagement currentFile = childFileList.get(i);
                    //若文件类型为文件 且文件密级符合用户密级
                    if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FILE && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                        String sourcePath = attachPath + File.separator + currentFile.getFileStorge();
                        //获取文件真实ID 若为逻辑树文件 则获取remark值
                        String fileRealId = String.valueOf(currentFile.getId());
                        if (currentFile.getParentType() == FileManagementContants.PARENT_TYPE_LOGICTREE) {
                            fileRealId = currentFile.getRemark();
                        }
                        SysUser sysUser = sysUserDao.getById(currentFile.getUploadPersonId());
                        String filePassword = SysFile.PASSWORD_PROJECT_NAME + "_" + sysUser.getAccount() + "_" + fileRealId;
                        ZipUtil.unZip(sourcePath, folderPath, filePassword);
                        //解压后修改名称
                        File unzipFile = new File(folderPath + File.separator + fileRealId + "." + currentFile.getFileFormat());
                        unzipFile.renameTo(new File(folderPath + File.separator + currentFile.getFileName() + "." + currentFile.getFileFormat()));
                    }
                    //若文件类型为文件夹 且文件密级符合用户密级
                    else if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FOLDER && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                        //先新建文件夹
                        String newPath = folderPath + File.separator + currentFile.getFileName();
                        File newdir = new File(newPath);
                        newdir.mkdirs();
                        //再查询该目录下所有文件
                        Map<String, Object> parentIdParams = new HashMap<>();
                        parentIdParams.put("parentId", currentFile.getId());
                        List<FileManagement> curChildFileList = fileManagementDao.getFileByFileName(parentIdParams);
                        //递归遍历所有文件
                        if (curChildFileList.size() > 0) {
                            this.createDownloadFileDir(curChildFileList, newPath, fileSecreatLevel, currentUser);
                        }
                    }
                }
                //目录组装完成后进行打包操作
                FileManagementService.compress(folderPath, downloadPath);
                File folder = new File(folderPath);
                if (folder.exists() && folder.canWrite()) {
                    FileUtil.deleteDir(folder);
                }
            }
        } else if (downloadFiles.length > 1) {
            String attachPath = SysFileService.getBasePath();
            //新建下载目录
            //为保证目录不重复 生成时间戳
            long time = System.currentTimeMillis();
            downloadPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator + time + File.separator + time + ".zip";
            String folderPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator + time + File.separator + time;
            File dir = new File(folderPath);
            dir.mkdirs();
            int downloadFilesLength = downloadFiles.length;
            for (int i = 0; i < downloadFilesLength; i++) {
                FileManagement currentFile = fileManagementDao.getById(downloadFiles[i]);
                if (currentFile == null) {
                    return FileManagementContants.DELETE_FILE_NO_FILE;
                }
                //若文件类型为文件 且文件密级符合用户密级
                if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FILE && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                    String sourcePath = attachPath + File.separator + currentFile.getFileStorge();
                    //获取文件真实ID 若为逻辑树文件 则获取remark值
                    String fileRealId = String.valueOf(currentFile.getId());
                    if (currentFile.getParentType() == FileManagementContants.PARENT_TYPE_LOGICTREE) {
                        fileRealId = currentFile.getRemark();
                    }
                    SysUser sysUser = sysUserDao.getById(currentFile.getUploadPersonId());
                    String filePassword = SysFile.PASSWORD_PROJECT_NAME + "_" + sysUser.getAccount() + "_" + fileRealId;
                    ZipUtil.unZip(sourcePath, folderPath, filePassword);
                    //解压后修改名称
                    File unzipFile = new File(folderPath + File.separator + fileRealId + "." + currentFile.getFileFormat());
                    unzipFile.renameTo(new File(folderPath + File.separator + currentFile.getFileName() + "." + currentFile.getFileFormat()));
                }
                //若文件类型为文件夹 且文件密级符合用户密级
                else if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FOLDER && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                    //先新建文件夹
                    String newPath = folderPath + File.separator + currentFile.getFileName();
                    File newdir = new File(newPath);
                    newdir.mkdirs();
                    //再查询该目录下所有文件
                    Map<String, Object> parentIdParams = new HashMap<String, Object>();
                    parentIdParams.put("parentId", currentFile.getId());
                    List<FileManagement> curChildFileList = fileManagementDao.getFileByFileName(parentIdParams);
                    //递归遍历所有文件
                    if (curChildFileList.size() > 0) {
                        this.createDownloadFileDir(curChildFileList, newPath, fileSecreatLevel, currentUser);
                    }
                }
            }
            //目录组装完成后进行打包操作
            FileManagementService.compress(folderPath, downloadPath);
            File folder = new File(folderPath);
            if (folder.exists() && folder.canWrite()) {
                FileUtil.deleteDir(folder);
            }
        }
        //删除压缩包
        final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1,
                new BasicThreadFactory.Builder().namingPattern("deleteFile-schedule-pool-%d").daemon(true).build());
        final String finalDownloadPath = downloadPath;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                File deleteFile = new File(finalDownloadPath);
                if (deleteFile.exists() && deleteFile.canWrite()) {
                    deleteFile.delete();
                    service.shutdown();
                } else if (!deleteFile.exists()) {
                    service.shutdown();
                }
            }
        };
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间 默认设置第一次删除时间为1分钟 若文件仍被使用 则每30分钟检测一次
        service.scheduleAtFixedRate(runnable, 1, 30, TimeUnit.MINUTES);
        //添加下载日志
        for (int i = 0; i < downloadFiles.length; i++) {
            FileManagement file = fileManagementDao.getById(downloadFiles[i]);
            fileManagementLogService.addLog(file.getId(), file.getFileName(), file.getFileStorge(), FileManagementContants.FILE_OPERATOR_DOWNLOAD);
        }
        return downloadPath;
    }

    /**
     * Zip压缩文件或者文件夹
     *
     * @param srcPathName 待压缩文件或者文件夹路径
     * @param zipFileName 压缩后压缩文件存放路径
     */
    public static void compress(String srcPathName, String zipFileName) {
        File file = new File(srcPathName);
        File zipFile = new File(zipFileName);
        if (!file.exists()) {
            throw new RuntimeException(srcPathName + "不存在！");
        }
        boolean isSuccessful = true;
        ZipOutputStream out = null;
        try {
            CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());
            out = new ZipOutputStream(cos);
            //配置压缩属性
            configCompressProperties(out);
            //执行压缩
            doCompress(file, out, "");
        } catch (Exception e) {
            isSuccessful = false;
            throw new RuntimeException(e);
        } finally {
            closeResource(out);
        }
    }

    /**
     * 执行压缩
     *
     * @param file    压缩文件/文件夹
     * @param out
     * @param basedir 输出文件地址
     */
    private static void doCompress(File file, ZipOutputStream out, String basedir) {
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            //压缩目录
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                doCompress(files[i], out, basedir + file.getName() + "/");
            }
            // 空文件夹的处理
            try {
                out.putNextEntry(new ZipEntry(basedir + file.getName() + "/"));
            } catch (Exception e) {

            }
        } else {
            //压缩文件
            BufferedInputStream bis = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(file));
                ZipEntry entry = new ZipEntry(basedir + file.getName());
                out.putNextEntry(entry);
                int count;
                byte data[] = new byte[BUFFER];
                while ((count = bis.read(data, 0, BUFFER)) != -1) {
                    out.write(data, 0, count);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                closeResource(bis);
            }
        }
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    private static String getNowStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }

    /**
     * 配置压缩属性
     *
     * @param out
     */
    private static void configCompressProperties(ZipOutputStream out) {
        //设置文件名编码方式
        out.setEncoding(encoding);
        //设置压缩说明
        out.setComment("\n压缩时间：" + getNowStr() + " \n");
    }


    /**
     * 创建下载目录
     *
     * @param curFileList      当前文件夹内容列表
     * @param filePath         当前文件夹真实路径
     * @param fileSecreatLevel 文件密级
     * @param currentUser      当前使用下载功能的用户
     */
    private void createDownloadFileDir(List<FileManagement> curFileList, String filePath, int[] fileSecreatLevel, SysUser currentUser) {
        int curChildFileListSize = curFileList.size();
        for (int i = 0; i < curChildFileListSize; i++) {
            FileManagement currentFile = curFileList.get(i);
            //设置文件组装路径
            String attachPath = SysFileService.getBasePath();
            //若文件类型为文件 且文件密级符合用户密级
            if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FILE && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                String sourcePath = attachPath + File.separator + currentFile.getFileStorge();
                //获取文件真实ID 若为逻辑树文件 则获取remark值
                String fileRealId = String.valueOf(currentFile.getId());
                if (currentFile.getParentType() == FileManagementContants.PARENT_TYPE_LOGICTREE) {
                    fileRealId = currentFile.getRemark();
                }
                SysUser sysUser = sysUserDao.getById(currentFile.getUploadPersonId());
                String filePassword = SysFile.PASSWORD_PROJECT_NAME + "_" + sysUser.getAccount() + "_" + fileRealId;
                ZipUtil.unZip(sourcePath, filePath, filePassword);
                //解压后修改名称
                File unzipFile = new File(filePath + File.separator + fileRealId + "." + currentFile.getFileFormat());
                unzipFile.renameTo(new File(filePath + File.separator + currentFile.getFileName() + "." + currentFile.getFileFormat()));
            }
            //若文件类型为文件夹 且文件密级符合用户密级
            else if (currentFile.getFileType() == FileManagementContants.FILE_TYPE_FOLDER && ArrayUtils.contains(fileSecreatLevel, currentFile.getFileSecretLevel())) {
                //先新建文件夹
                String newPath = filePath + File.separator + currentFile.getFileName();
                File dir = new File(newPath);
                dir.mkdirs();
                //再查询该目录下所有文件
                Map<String, Object> parentIdParams = new HashMap<>();
                parentIdParams.put("parentId", currentFile.getId());
                List<FileManagement> curChildFileList = fileManagementDao.getFileByFileName(parentIdParams);
                //递归遍历所有文件
                if (curChildFileList.size() > 0) {
                    this.createDownloadFileDir(curChildFileList, newPath, fileSecreatLevel, currentUser);
                }
            }
        }
    }

    //------------------------------------------------文件解压/压缩工具-------------------------------------------------------------------------------------
    private static final int BUFFER = 8192;

    /**
     * 设置压缩编码，解决中文文件名乱码问题
     */
    private static final String encoding = System.getProperty("sun.jnu.encoding");

    static {
        /**
         * 解压依据的编码是sun.zip.encoding 所以需要设置 解压编码
         */
        System.setProperty("sun.zip.encoding", encoding);
    }

    /**
     * 释放资源
     *
     * @param resources
     */
    private static void closeResource(Closeable... resources) {
        if (resources == null || resources.length < 1) {
            return;
        }
        for (Closeable cur : resources) {
            if (cur == null) {
                continue;
            }
            if (cur instanceof ZipInputStream) {
                ZipInputStream zis = (ZipInputStream) cur;
                try {
                    zis.closeEntry();
                } catch (IOException e) {
                }
            }
            if (cur instanceof ZipOutputStream) {
                ZipOutputStream zos = (ZipOutputStream) cur;
                try {
                    zos.closeEntry();
                } catch (IOException e) {
                }
            }
            try {
                cur.close();
            } catch (IOException e) {
            }
        }
    }


    /**
     * 通过父节点查询下一级所有文件
     *
     * @param folder           字典类型
     * @param fileSecretLevels 文件密级
     * @return 下一级所有文件List
     */
    public List<FileManagement> getFilesByParentIdAndSecret(String folder, int[] fileSecretLevels) {
        Map<String, Object> params = new HashMap<>();
        params.put("parentId", folder);
        params.put("fileSecretLevels", fileSecretLevels);
        return fileManagementDao.getFilesByCondition(params);
    }
}
